package com.specter.dev.code.execute;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import com.specter.dev.code.builder.GenConfiguration.ModuleInput;
import com.specter.utils.StringUtils;

import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import lombok.extern.slf4j.Slf4j;

/**
 * Note:通过扫描实体包来完成实体类搜索<br/>
 * <br/>
 * <b> &lt;input type="package" src="cn.liangthink.*.entity;*.entity" tgt="a,b"
 * fix="%s+Entity" /&gt; </b>
 * 
 * 后面改为通过com.thoughtworks.qdox来实现
 * 
 * @author Liang.Wang
 * @version Mar 23, 2017
 */
@Slf4j
public class ModuleInputExe4Package implements ModuleInputExe {

	private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {new AnnotationTypeFilter(jakarta.persistence.Entity.class, false) };

	@Override
	public List<?> input(ModuleInput input) {

		ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver();
		MetadataReaderFactory mrf = new CachingMetadataReaderFactory(rpr);

		TypeFilter nf = new RegexPatternTypeFilter(Pattern.compile(input.getTgt()));// 单独的名字过滤器
		List<ModuleInputExe.Entity> list = new ArrayList<>();
		try {
			for (String pkg : input.getSrc().split(";")) {
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
						+ ClassUtils.convertClassNameToResourcePath(pkg) + "/**/*.class";

				for (Resource resource : rpr.getResources(pattern)) {
					if (resource.isReadable()) {
						MetadataReader reader = mrf.getMetadataReader(resource);
						String className = reader.getClassMetadata().getClassName();

						for (TypeFilter filter : DEFAULT_ENTITY_TYPE_FILTERS) {// 按照正则表达式进行过滤
							if (filter.match(reader, mrf) && nf.match(reader, mrf)) {// 同时过滤类型和类名称
								Class<?> clazz = rpr.getClassLoader().loadClass(className);
								list.add(this.parse(clazz));
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * 将注解的类解析成描述信息
	 * 
	 * @param clazz 注解的实体类型
	 * @return 解析的类信息
	 */
	private ModuleInputExe.Entity parse(Class<?> clazz) {
		ModuleInputExe.Entity entity = new ModuleInputExe.Entity();
		entity.setClassName(clazz.getName());
		entity.setEntityName(clazz.getSimpleName());

		Table t = clazz.getAnnotation(Table.class);
		if (t != null) {
			entity.setTableName(t.name());
			entity.setTableSchema(t.schema());
		} else {// 没有注解默认生成
			entity.setTableName(StringUtils.toDataName(entity.getEntityName()));
			entity.setTableSchema(null);
		}

		List<ModuleInputExe.EntityProperty> properties = new ArrayList<>();
		try {
			for (Field f : clazz.getDeclaredFields()) {
				if (f.getAnnotation(Transient.class) != null || "serialVersionUID".equals(f.getName())) {// 过滤不被解析的字段
					continue;
				}

				ModuleInputExe.EntityProperty property = new ModuleInputExe.EntityProperty();
				property.setName(f.getName());
				property.setClazz(StringUtils.remove(f.getType().getName(), "java.lang."));

				Column col = f.getAnnotation(Column.class);
				if (col != null) {
					property.setColumn(col.name());
				} else {// 没有注解默认生成
					property.setColumn(StringUtils.toDataName(f.getName()));
				}
				property.setType(f.getType().getSimpleName());// 无法获取以java类型替代
				property.setRemark("field:" + f.getName());// 无法获取以java字段名替代

				if (f.getAnnotation(Id.class) != null) {// Id字段
					entity.setId(property);
				} else {
					properties.add(property);
				}
			}
		} catch (Exception e) {
			log.error("{} parse error,please check it !", entity.getClass().getSimpleName());
			e.printStackTrace();
		}
		entity.setProperties(properties);
		return entity;
	}
}
